/*
 * @file:ble_ftms.h
 *
 * @date: 2019-7-20
 * @author: l00357454
 */

#include "ble_ftms.h"
// #include "ble_ftms_server.h"
#include "string.h"
#include "ftmp_uart.h"

extern hw_u8 GetFitnessMachineStatus(void);

extern int SendUartDataToApp(hw_u8 *data, hw_u8 length, hw_u8 uuidIndex);

extern void SendAppExtensionDataToUart(huawei_fitness_extension_data_t *extensionData);

extern void SendAppMachineControlPointToUart(hw_u8 opCode, control_point_target_union *param);

void SetControlPermissionToSuccess(void);

void ResetControlPermission(void);

hw_u8 HandleControlPointCollision(hw_u8 opCode);

static hw_u8 g_trainingStatus = 0x00;

static hw_u8 g_controlPointStatus = verify_failed;

static hw_u8 g_FitnessMachineStatus = status_reset; // 健身机器状态状态

static unsigned int g_byteOrder = 0x00;
static unsigned int g_pduSize = 20; //默认20 ，做分片处理

#define HW_LITTLE_ENDIAN 0x01
#define HW_BIG_ENDIAN 0x02
#define HW_BLUETOOTH_ENDIAN HW_LITTLE_ENDIAN // 蓝牙是小端序

static inline void GetByteOrder()
{
	if (g_byteOrder)
	{
		return;
	}
	unsigned short hostData = 0x1234;
	unsigned char *orderData = (unsigned char *)&hostData;
	if (orderData[0] == 0x34)
	{
		g_byteOrder = HW_LITTLE_ENDIAN;
	}
	else
	{
		g_byteOrder = HW_BIG_ENDIAN;
	}
	return;
}

static inline unsigned short hostSToBTOrder(unsigned short host)
{
	GetByteOrder();
	if (g_byteOrder == HW_BLUETOOTH_ENDIAN)
	{
		return host;
	}
	unsigned short btData = host;
	unsigned char *orderData = (unsigned char *)&btData;
	unsigned char tmp = orderData[0];
	orderData[0] = orderData[1];
	orderData[1] = tmp;
	return btData;
}

static inline void CopyShortOrIntToBT(void *hostData, int hostLen, void *btData, int btDataLen)
{
	int i;

	GetByteOrder();

	if (g_byteOrder == HW_BLUETOOTH_ENDIAN)
	{
		for (i = 0; i < btDataLen && i < hostLen; i++)
		{
			((unsigned char *)btData)[i] = ((unsigned char *)hostData)[i];
		}
	}
	else
	{
		for (i = 0; i < btDataLen && i < hostLen; i++)
		{
			((unsigned char *)btData)[i] = ((unsigned char *)hostData)[hostLen - i - 1];
		}
	}
	return;
}

void SetPDUSize(unsigned int size)
{
	g_pduSize = size;
	return;
}

int GetPDUSize()
{
	return g_pduSize;
}

#ifdef HWGYM_CROSSTRAINER // 交叉训练器
int CrossTrainerDataAccessNotify(CROSS_TRAINER_DATA_T *data)
{
	if (!data)
	{
		return HW_ERR; // null pointer
	}

	unsigned char crossTrainerData[CROSS_TRAINER_DATA_MAXLEN + 1] = {0};
	unsigned int flag = data->Flags;
	unsigned int sndFlag = 0;
	unsigned int dataLen = 0;
	unsigned int deltaLen = 0;
	unsigned int optionLen = 0;

	if (!(flag & CROSS_TRAINER_INSTANTANEOUS_SPEED))
	{ // Instantaneous_Speed必须有
		return HW_ERR;
	}

	dataLen += 3; // 预留Flag位置 24bits

	for (int i = CROSS_TRAINER_FIELD_LOOP_INIT; i <= CROSS_TRAINER_FIELD_LOOP_END; i++)
	{
		switch (flag & (0x00000001 << i))
		{
		case CROSS_TRAINER_INSTANTANEOUS_SPEED:
			CopyShortOrIntToBT(&(data->Instantaneous_Speed), sizeof(unsigned short), crossTrainerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			optionLen = deltaLen = sizeof(unsigned short);
			break;
		case CROSS_TRAINER_AVERAGE_SPEED:
			CopyShortOrIntToBT(&(data->Average_Speed), sizeof(unsigned short), crossTrainerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= CROSS_TRAINER_AVERAGE_SPEED;
			break;
		case CROSS_TRAINER_TOTAL_DISTANCE:
			CopyShortOrIntToBT(&(data->Total_Distance), sizeof(unsigned int), crossTrainerData + dataLen, 3);
			dataLen += 3;
			deltaLen = 3;
			sndFlag |= CROSS_TRAINER_TOTAL_DISTANCE;
			break;
		case CROSS_TRAINER_STEP_COUNT:
			CopyShortOrIntToBT(&(data->Step_Per_Minute), sizeof(unsigned short), crossTrainerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			CopyShortOrIntToBT(&(data->Average_Step_Rate), sizeof(unsigned short), crossTrainerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short) * 2;
			sndFlag |= CROSS_TRAINER_STEP_COUNT;
			break;
		case CROSS_TRAINER_STRIDE_COUNT:
			CopyShortOrIntToBT(&(data->Stride_Count), sizeof(unsigned short), crossTrainerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= CROSS_TRAINER_STRIDE_COUNT;
			break;
		case CROSS_TRAINER_ELEVATION_GAIN:
			CopyShortOrIntToBT(&(data->Positive_Elevation_Gain), sizeof(unsigned short), crossTrainerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			CopyShortOrIntToBT(&(data->Negative_Elevation_Gain), sizeof(unsigned short), crossTrainerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short) * 2;
			sndFlag |= CROSS_TRAINER_ELEVATION_GAIN;
			break;
		case CROSS_TRAINER_INCLINATION_RAMP_ANGLE_SETTING:
			CopyShortOrIntToBT(&(data->Inclination), sizeof(unsigned short), crossTrainerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			CopyShortOrIntToBT(&(data->Ramp_Angle_Setting), sizeof(unsigned short), crossTrainerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short) * 2;
			sndFlag |= CROSS_TRAINER_INCLINATION_RAMP_ANGLE_SETTING;
			break;
		case CROSS_TRAINER_RESISTANCE_LEVEL:
			CopyShortOrIntToBT(&(data->Resistance_Level), sizeof(unsigned short), crossTrainerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= CROSS_TRAINER_RESISTANCE_LEVEL;
			break;
		case CROSS_TRAINER_INSTANTANEOUS_POWER:
			CopyShortOrIntToBT(&(data->Instantaneous_Power), sizeof(unsigned short), crossTrainerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= CROSS_TRAINER_INSTANTANEOUS_POWER;
			break;
		case CROSS_TRAINER_AVERAGE_POWER:
			CopyShortOrIntToBT(&(data->Average_Power), sizeof(unsigned short), crossTrainerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= CROSS_TRAINER_AVERAGE_POWER;
			break;
		case CROSS_TRAINER_EXPENDED_ENERGY:
			CopyShortOrIntToBT(&(data->Total_Energy), sizeof(unsigned short), crossTrainerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			CopyShortOrIntToBT(&(data->Energy_Per_Hour), sizeof(unsigned short), crossTrainerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			crossTrainerData[dataLen] = data->Energy_Per_Minute;
			dataLen += 1;
			deltaLen = sizeof(unsigned short) * 2 + 1;
			sndFlag |= CROSS_TRAINER_EXPENDED_ENERGY;
			break;
		case CROSS_TRAINER_HEART_RATE:
			crossTrainerData[dataLen] = data->Heart_Rate;
			dataLen += 1;
			deltaLen = 1;
			sndFlag |= CROSS_TRAINER_HEART_RATE;
			break;
		case CROSS_TRAINER_METABOLIC_EQUIVALENT:
			crossTrainerData[dataLen] = data->Metabolic_Equivalent;
			dataLen += 1;
			deltaLen = 1;
			sndFlag |= CROSS_TRAINER_METABOLIC_EQUIVALENT;
			break;
		case CROSS_TRAINER_ELAPSED_TIME:
			CopyShortOrIntToBT(&(data->Elapsed_Time), sizeof(unsigned short), crossTrainerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= CROSS_TRAINER_ELAPSED_TIME;
			break;
		case CROSS_TRAINER_REMAINING_TIME:
			CopyShortOrIntToBT(&(data->Remaining_Time), sizeof(unsigned short), crossTrainerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= CROSS_TRAINER_REMAINING_TIME;
			break;
		case CROSS_TRAINER_MOVEMENT_DIRECTION:
			sndFlag |= CROSS_TRAINER_MOVEMENT_DIRECTION;
			break;
		default:
			break;
		}

		if (dataLen > g_pduSize)
		{
			sndFlag |= 0x00000001; // more data
			sndFlag = sndFlag & (~(0x00000001 << i));
			dataLen = dataLen - deltaLen;
			i--;

			CopyShortOrIntToBT(&(sndFlag), sizeof(unsigned int), crossTrainerData + optionLen, 3);
			dataLen = dataLen - optionLen;
			SendUartDataToApp(crossTrainerData + optionLen, dataLen, CROSS_TRAINER_DATA_NO);

			// 下一个PDU
			sndFlag = 0;
			dataLen = 3; // 预留Flag位置 24bits
			CopyShortOrIntToBT(&(data->Instantaneous_Speed), sizeof(unsigned short), crossTrainerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
		}
	}

	CopyShortOrIntToBT(&sndFlag, sizeof(unsigned int), crossTrainerData, 3);

	SendUartDataToApp(crossTrainerData, dataLen, CROSS_TRAINER_DATA_NO);

	return HW_OK;
}
#endif

#ifdef HWGYM_ROWER
int RowerDataAccessNotify(ROWER_DATA_T *data)
{

	if (!data)
	{
		return HW_ERR; // null pointer
	}

	unsigned char rowerData[ROWER_DATA_MAXLEN + 1] = {0};
	unsigned short flag = data->Flags;
	unsigned short sndFlag = 0;
	unsigned int dataLen = 0;
	unsigned int deltaLen = 0;
	unsigned int optionLen = 0;

	if (!(flag & ROWER_STROKE_RATE_STROKE_COUNT))
	{ // Stroke_Rate & Stroke_Count必须有
		return HW_ERR;
	}

	dataLen += sizeof(unsigned short); // 预留Flag位置

	for (int i = ROWER_FIELD_LOOP_INIT; i <= ROWER_FIELD_LOOP_END; i++)
	{
		switch (flag & (0x0001 << i))
		{
		case ROWER_STROKE_RATE_STROKE_COUNT:
			rowerData[dataLen] = data->Stroke_Rate;
			dataLen += 1;
			CopyShortOrIntToBT(&(data->Stroke_Count), sizeof(unsigned short), rowerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			optionLen = deltaLen = sizeof(unsigned short) + 1;
			break;
		case ROWER_AVERAGE_STROKE_RATE:
			rowerData[dataLen] = data->Average_Stroke_Rate;
			dataLen += 1;
			deltaLen = 1;
			sndFlag |= ROWER_AVERAGE_STROKE_RATE;
			break;
		case ROWER_TOTAL_DISTANCE:
			CopyShortOrIntToBT(&(data->Total_Distance), sizeof(unsigned int), rowerData + dataLen, 3);
			dataLen += 3;
			deltaLen = 3;
			sndFlag |= ROWER_TOTAL_DISTANCE;
			break;
		case ROWER_INSTANTANEOUS_PACE:
			CopyShortOrIntToBT(&(data->Instantaneous_Pace), sizeof(unsigned short), rowerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= ROWER_INSTANTANEOUS_PACE;
			break;
		case ROWER_AVERAGE_PACE:
			CopyShortOrIntToBT(&(data->Average_Pace), sizeof(unsigned short), rowerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= ROWER_AVERAGE_PACE;
			break;
		case ROWER_INSTANTANEOUS_POWER:
			CopyShortOrIntToBT(&(data->Instantaneous_Power), sizeof(unsigned short), rowerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= ROWER_INSTANTANEOUS_POWER;
			break;
		case ROWER_AVERAGE_POWER:
			CopyShortOrIntToBT(&(data->Average_Power), sizeof(unsigned short), rowerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= ROWER_AVERAGE_POWER;
			break;
		case ROWER_RESISTANCE_LEVEL:
			CopyShortOrIntToBT(&(data->Resistance_Level), sizeof(unsigned short), rowerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= ROWER_RESISTANCE_LEVEL;
			break;
		case ROWER_EXPENDED_ENERGY:
			CopyShortOrIntToBT(&(data->Total_Energy), sizeof(unsigned short), rowerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			CopyShortOrIntToBT(&(data->Energy_Per_Hour), sizeof(unsigned short), rowerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			rowerData[dataLen] = data->Energy_Per_Minute;
			dataLen += 1;
			deltaLen = sizeof(unsigned short) * 2 + 1;
			sndFlag |= ROWER_EXPENDED_ENERGY;
			break;
		case ROWER_HEART_RATE:
			rowerData[dataLen] = data->Heart_Rate;
			dataLen += 1;
			deltaLen = 1;
			sndFlag |= ROWER_HEART_RATE;
			break;
		case ROWER_METABOLIC_EQUIVALENT:
			rowerData[dataLen] = data->Metabolic_Equivalent;
			dataLen += 1;
			deltaLen = 1;
			sndFlag |= ROWER_METABOLIC_EQUIVALENT;
			break;
		case ROWER_ELAPSED_TIME:
			CopyShortOrIntToBT(&(data->Elapsed_Time), sizeof(unsigned short), rowerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= ROWER_ELAPSED_TIME;
			break;
		case ROWER_REMAINING_TIME:
			CopyShortOrIntToBT(&(data->Remaining_Time), sizeof(unsigned short), rowerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= ROWER_REMAINING_TIME;
			break;
		default:
			break;
		}

		if (dataLen > g_pduSize)
		{
			sndFlag |= 0x0001; // more data
			sndFlag = sndFlag & (~(0x0001 << i));
			dataLen = dataLen - deltaLen;
			i--;

			CopyShortOrIntToBT(&(sndFlag), sizeof(unsigned short), rowerData + optionLen, sizeof(unsigned short));
			dataLen = dataLen - optionLen;
			SendUartDataToApp(rowerData + optionLen, dataLen, ROWER_DATA_NO);

			// 下一个PDU
			sndFlag = 0;
			dataLen = sizeof(unsigned short);
			rowerData[dataLen] = data->Stroke_Rate;
			dataLen += 1;
			CopyShortOrIntToBT(&(data->Stroke_Count), sizeof(unsigned short), rowerData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short) + 1;
		}
	}

	CopyShortOrIntToBT(&sndFlag, sizeof(unsigned short), rowerData, sizeof(unsigned short));

	SendUartDataToApp(rowerData, dataLen, ROWER_DATA_NO);

	return HW_OK;
}
#endif

#ifdef HWGYM_INDOORBIKE
int IndoorBikeDataAccessNotify(INDOOR_BIKE_DATA_T *data)
{
	if (!data)
	{
		return HW_ERR; // null pointer
	}
	unsigned char indoorBikeData[INDOOR_BIKE_DATA_MAXLEN + 1] = {0};
	unsigned short flag = data->Flags;
	unsigned short sndFlag = 0;
	unsigned int dataLen = 0;
	unsigned int deltaLen = 0;
	unsigned int optionLen = 0;

	if (!(flag & INDOOR_BIKE_INSTANTANEOUS_SPEED))
	{ // Instantaneous_Speed必须有
		return HW_ERR;
	}

	dataLen += sizeof(unsigned short); // 预留Flag位置

	for (int i = INDOOR_BIKE_FIELD_LOOP_INIT; i <= INDOOR_BIKE_FIELD_LOOP_END; i++)
	{
		switch (flag & (0x0001 << i))
		{
		case INDOOR_BIKE_INSTANTANEOUS_SPEED:
			CopyShortOrIntToBT(&(data->Instantaneous_Speed), sizeof(unsigned short), indoorBikeData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			optionLen = deltaLen = sizeof(unsigned short);
			break;
		case INDOOR_BIKE_AVERAGE_SPEED:
			CopyShortOrIntToBT(&(data->Average_Speed), sizeof(unsigned short), indoorBikeData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= INDOOR_BIKE_AVERAGE_SPEED;
			break;
		case INDOOR_BIKE_INSTANTANEOUS_CADENCE:
			CopyShortOrIntToBT(&(data->Instantaneous_Cadence), sizeof(unsigned short), indoorBikeData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= INDOOR_BIKE_INSTANTANEOUS_CADENCE;
			break;
		case INDOOR_BIKE_AVERAGE_CADENCE:
			CopyShortOrIntToBT(&(data->Average_Cadence), sizeof(unsigned short), indoorBikeData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= INDOOR_BIKE_AVERAGE_CADENCE;
			break;
		case INDOOR_BIKE_TOTAL_DISTANCE:
			CopyShortOrIntToBT(&(data->Total_Distance), sizeof(unsigned int), indoorBikeData + dataLen, 3);
			dataLen += 3;
			deltaLen = 3;
			sndFlag |= INDOOR_BIKE_TOTAL_DISTANCE;
			break;
		case INDOOR_BIKE_RESISTANCE_LEVEL:
			CopyShortOrIntToBT(&(data->Resistance_Level), sizeof(unsigned short), indoorBikeData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= INDOOR_BIKE_RESISTANCE_LEVEL;
			break;
		case INDOOR_BIKE_INSTANTANEOUS_POWER:
			CopyShortOrIntToBT(&(data->Instantaneous_Power), sizeof(unsigned short), indoorBikeData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= INDOOR_BIKE_INSTANTANEOUS_POWER;
			break;
		case INDOOR_BIKE_AVERAGE_POWER:
			CopyShortOrIntToBT(&(data->Average_Power), sizeof(unsigned short), indoorBikeData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= INDOOR_BIKE_AVERAGE_POWER;
			break;
		case INDOOR_BIKE_EXPENDED_ENERGY:
			CopyShortOrIntToBT(&(data->Total_Energy), sizeof(unsigned short), indoorBikeData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			CopyShortOrIntToBT(&(data->Energy_Per_Hour), sizeof(unsigned short), indoorBikeData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			indoorBikeData[dataLen] = data->Energy_Per_Minute;
			dataLen += 1;
			deltaLen = sizeof(unsigned short) * 2 + 1;
			sndFlag |= INDOOR_BIKE_EXPENDED_ENERGY;
			break;
		case INDOOR_BIKE_HEART_RATE:
			indoorBikeData[dataLen] = data->Heart_Rate;
			dataLen += 1;
			deltaLen = 1;
			sndFlag |= INDOOR_BIKE_HEART_RATE;
			break;
		case INDOOR_BIKE_METABOLIC_EQUIVALENT:
			indoorBikeData[dataLen] = data->Metabolic_Equivalent;
			dataLen += 1;
			deltaLen = 1;
			sndFlag |= INDOOR_BIKE_METABOLIC_EQUIVALENT;
			break;
		case INDOOR_BIKE_ELAPSED_TIME:
			CopyShortOrIntToBT(&(data->Elapsed_Time), sizeof(unsigned short), indoorBikeData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= INDOOR_BIKE_ELAPSED_TIME;
			break;
		case INDOOR_BIKE_REMAINING_TIME:
			CopyShortOrIntToBT(&(data->Remaining_Time), sizeof(unsigned short), indoorBikeData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= INDOOR_BIKE_REMAINING_TIME;
			break;
		default:
			break;
		}

		if (dataLen > g_pduSize)
		{
			sndFlag |= 0x0001; // more data
			sndFlag = sndFlag & (~(0x0001 << i));
			dataLen = dataLen - deltaLen;
			i--;
			CopyShortOrIntToBT(&(sndFlag), sizeof(unsigned short), indoorBikeData + optionLen, sizeof(unsigned short));
			dataLen = dataLen - optionLen;
			SendUartDataToApp(indoorBikeData + optionLen, dataLen, ORDER_INDOOR_BIKE_DATA);

			// 下一个PDU
			sndFlag = 0;
			dataLen = sizeof(unsigned short);
			CopyShortOrIntToBT(&(data->Instantaneous_Speed), sizeof(unsigned short), indoorBikeData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
		}
	}

	CopyShortOrIntToBT(&sndFlag, sizeof(unsigned short), indoorBikeData, sizeof(unsigned short));

	SendUartDataToApp(indoorBikeData, dataLen, ORDER_INDOOR_BIKE_DATA);

	return HW_OK;
}
#endif

#ifdef HWGYM_TREADMILL
int TreadmillDataAccessNotify(TREADMILL_DATA_T *data_value)
{
	if (!data_value)
	{
		return HW_ERR; // null pointer  空指针
	}
	unsigned char treadmillData[TREADMILL_DATA_MAXLEN + 1] = {0};
	unsigned short flag = data_value->flags;
	unsigned short sndFlag = 0;
	unsigned int dataLen = 0;
	unsigned int deltaLen = 0;
	unsigned int optionLen = 0;
	dataLen += sizeof(unsigned short); // 预留Flag位置
	if ((flag & 0x0001) == 0)		   // Instantaneous_Speed必须有
	{
		CopyShortOrIntToBT(&(data_value->instantaneousSpeed), sizeof(unsigned short), treadmillData + dataLen, sizeof(unsigned short));
		dataLen += sizeof(unsigned short);
		optionLen = deltaLen = sizeof(unsigned short);
	}
	for (int i = TREADMILL_FIELD_LOOP_INIT; i <= TREADMILL_FIELD_LOOP_END; i++)
	{
		switch (flag & (0x0001 << i))
		{
		case treadmill_average_speed:
			CopyShortOrIntToBT(&(data_value->averageSpeed), sizeof(unsigned short), treadmillData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= treadmill_average_speed;
			break;
		case treadmill_total_distance:
			CopyShortOrIntToBT(&(data_value->totalDistance), sizeof(unsigned long), treadmillData + dataLen, 3);
			dataLen += 3;
			deltaLen = 3;
			sndFlag |= treadmill_total_distance;
			break;
		case inclination_and_ramp_angle_setting:
			CopyShortOrIntToBT(&(data_value->inclination), sizeof(unsigned short), treadmillData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			CopyShortOrIntToBT(&(data_value->rampAngle), sizeof(unsigned short), treadmillData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= inclination_and_ramp_angle_setting;
			break;
		case treadmill_elevation_gain:
			CopyShortOrIntToBT(&(data_value->positiveElevationGain), sizeof(unsigned short), treadmillData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			CopyShortOrIntToBT(&(data_value->negativeElevationGain), sizeof(unsigned short), treadmillData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= treadmill_elevation_gain;
			break;
		case instantaneous_pace:
			treadmillData[dataLen] = data_value->Instantaneous_Pace;
			dataLen += sizeof(unsigned char);
			deltaLen = sizeof(unsigned char);
			sndFlag |= instantaneous_pace;
			break;
		case average_pace:
			treadmillData[dataLen] = data_value->Average_Pace;
			dataLen += sizeof(unsigned char);
			deltaLen = sizeof(unsigned char);
			sndFlag |= average_pace;
			break;
		case treadmill_expended_energy:
			CopyShortOrIntToBT(&(data_value->totalEnergy), sizeof(unsigned short), treadmillData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			CopyShortOrIntToBT(&(data_value->energyPerHour), sizeof(unsigned short), treadmillData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			treadmillData[dataLen] = data_value->energyPerMinute;
			dataLen += sizeof(unsigned char);
			deltaLen = sizeof(unsigned short) * 2 + 1;
			;
			sndFlag |= treadmill_expended_energy;
			break;
		case heart_rate:
			treadmillData[dataLen] = data_value->heartRate;
			dataLen += sizeof(unsigned char);
			deltaLen = sizeof(unsigned char);
			sndFlag |= heart_rate;
			break;
		case treadmill_metabolic_equivalent:
			treadmillData[dataLen] = data_value->Metabolic_Equivalent;
			dataLen += sizeof(unsigned char);
			deltaLen = sizeof(unsigned char);
			sndFlag |= treadmill_metabolic_equivalent;
			break;
		case treadmill_elapsed_time:
			CopyShortOrIntToBT(&(data_value->elapsedTime), sizeof(unsigned short), treadmillData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= treadmill_elapsed_time;
			break;
		case treadmill_remaining_time:
			CopyShortOrIntToBT(&(data_value->Remaining_Time), sizeof(unsigned short), treadmillData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
			sndFlag |= treadmill_remaining_time;
			break;
		case treadmill_force_on_belt_and_power_output:
			CopyShortOrIntToBT(&(data_value->Force_on_Belt), sizeof(signed short), treadmillData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(signed short);
			CopyShortOrIntToBT(&(data_value->Power_Output), sizeof(signed short), treadmillData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(signed short);
			deltaLen = 2 * sizeof(signed short);
			sndFlag |= treadmill_force_on_belt_and_power_output;
			break;
		default:
			break;
		}
		if (dataLen > g_pduSize)
		{
            sndFlag |= 0x0001;   // more data
            sndFlag = sndFlag & (~(0x0001 << i));
			dataLen = dataLen - deltaLen;
			i--;
			CopyShortOrIntToBT(&sndFlag, sizeof(unsigned short), treadmillData + optionLen, sizeof(unsigned short));
			dataLen = dataLen - optionLen;
			SendUartDataToApp(treadmillData + optionLen, dataLen, ORDER_TREADMILL_DATA);
		//	app_gatt_treadmill_data_notify_data(treadmillData + optionLen, dataLen);
			// 下一个PDU
			sndFlag = 0;
			dataLen = sizeof(unsigned short);
			CopyShortOrIntToBT(&(data_value->instantaneousSpeed), sizeof(unsigned short), treadmillData + dataLen, sizeof(unsigned short));
			dataLen += sizeof(unsigned short);
			deltaLen = sizeof(unsigned short);
		}
	}

	CopyShortOrIntToBT(&sndFlag, sizeof(unsigned short), treadmillData, sizeof(unsigned short));
	SendUartDataToApp(treadmillData, dataLen, ORDER_TREADMILL_DATA);
//	app_gatt_treadmill_data_notify_data(treadmillData , dataLen);
	return HW_OK;
}
#endif

void BleStateRequest(void)
{
	SendUartDataToApp(NULL, 0, ORDER_BLE_STATUS);
}
void BleStateSet(hw_u8 data_value)
{
	SendUartDataToApp(&data_value, 1, ORDER_SET_BLE_STATUS);
}
void ModelWrite(hw_u8 *p_data, hw_u16 length)
{
	SendUartDataToApp(p_data, length, ORDER_MODEL);
}
void SpeedUnitslWrite(hw_u8 data_value)
{
	SendUartDataToApp(&data_value, 1, ORDER_SPEED_UNITS);
}
void HardwareVersionWrite(hw_u8 *p_data, hw_u16 length)
{
	SendUartDataToApp(p_data, length, ORDER_HARDWARE_REVISION_STRING);
}
void McuNotice(hw_u8 *p_data, hw_u16 length)
{
	SendUartDataToApp(p_data, length, ORDER_MCU_NOTICE);
}
/**
 * 第一位为对应service下 Characteristics 的序号，此处对应fitness_machine_Attributes结构体数组第一个元素
 *
 */
void FitnessMachineFeatureAccessWrite(hw_u32 featureField, hw_u32 targetSettingFeatures)
{
	hw_u8 feature[8] = {0x00};
	for (int i = 0; i < 4; i++)
	{
		feature[i] = (featureField >> (i * 8)) & 0xFF;
		feature[i + 4] = (targetSettingFeatures >> (i * 8)) & 0xFF;
	}
	SendUartDataToApp(feature, 0x08, ORDER_FITNESS_MACHINE_FEATURE);
}
/**
 * Characteristics为fitness_machine_Attributes数组第3个元素
 * 返回一个2个字节的数组
 * 支持notify
 */
void TrainingStatusAccessWrite(hw_u8 trainingStatus)
{
	hw_u8 status[2];
	status[0] = 0x01;			// 无扩展字段
	status[1] = trainingStatus; // 第二个字节为状态值
	g_trainingStatus = trainingStatus;
	SendUartDataToApp(status, 0x02, ORDER_TRAINING_STATUS);
}

void SpeedRangeWrite(hw_u16 minSpeed, hw_u16 maxSpeed, hw_u16 minIncrement)
{
	hw_u8 speedRange[6];
	for (int i = 0; i < 2; i++)
	{
		speedRange[i] = (minSpeed >> (i * 8)) & 0xFF;
		speedRange[i + 2] = (maxSpeed >> (i * 8)) & 0xFF;
		speedRange[i + 4] = (minIncrement >> (i * 8)) & 0xFF;
	}
	SendUartDataToApp(speedRange, 0x06, ORDER_SPEED_RANGE);
}

void InclinationRangeWrite(hw_s16 minInclination, hw_s16 maxInclination, hw_u16 minIncrement)
{
	hw_u8 inclinationRange[6];
	for (int i = 0; i < 2; i++)
	{
		inclinationRange[i] = (minInclination >> (i * 8)) & 0xFF;
		inclinationRange[i + 2] = (maxInclination >> (i * 8)) & 0xFF;
		inclinationRange[i + 4] = (minIncrement >> (i * 8)) & 0xFF;
	}
	SendUartDataToApp(inclinationRange, 0x06, ORDER_INCLINATION_RANGE);
}
#if 0
void ResistanceLevelRangeWrite(hw_s16 minLevel, hw_s16 maxLevel, hw_u16 minIncrement)
{
	hw_u8 resistanceLevelRange[6];
	for (int i = 0; i < 2; i++)
	{
		resistanceLevelRange[i] = (minLevel >> (i * 8)) & 0xFF;
		resistanceLevelRange[i + 2] = (maxLevel >> (i * 8)) & 0xFF;
		resistanceLevelRange[i + 4] = (minIncrement >> (i * 8)) & 0xFF;
	}
	SendUartDataToApp(resistanceLevelRange, 0x06, ORDER_RESISTANCE_LEVEL);
}
#endif
void HeartRateRangeWrite(hw_u8 minHeartRate, hw_u8 maxHeartRate, hw_u8 minIncrement)
{
	hw_u8 heartRateRange[3];
	heartRateRange[0] = minHeartRate;
	heartRateRange[1] = maxHeartRate;
	heartRateRange[2] = minIncrement;
	SendUartDataToApp(heartRateRange, 0x03, ORDER_HEART_RATE_RANGE);
}

void PowerRangeWrite(signed short minPower, signed short maxPower, unsigned short minIncrement)
{
	unsigned char powerRange[6] = {0};
	unsigned short *data = (unsigned short *)powerRange;
	*data = hostSToBTOrder((unsigned short)(minPower));
	*(data + 1) = hostSToBTOrder((unsigned short)(maxPower));
	*(data + 2) = hostSToBTOrder((minIncrement));
	SendUartDataToApp(powerRange, 0x06, ORDER_POWER_RANGE);
}
void FitnessMachineControlPointWrite(hw_u8 *pBuf, hw_u8 length)
{
	if (pBuf == NULL || length <= 0)
	{
		return;
	}
	control_point_target_union param;
	hw_u8 opCode = pBuf[0];
	param.response_state =  operation_failed; // 回复APP  操作失败
	if (opCode == request_control)
	{ // 请求控制权限，设置权限标记位为同意
		SetControlPermissionToSuccess();
		param.response_state =  success; // 回复APP  
	}
	if (g_controlPointStatus == verify_failed)
	{ // 没有申请到权限，不响应控制指令
		FitnessMachineControlPointResponse(opCode, control_not_permitted);
		return;
	}
	if (opCode == reset)
	{ // 重置权限控制指令
		ResetControlPermission();
	}
	else
	{
		hw_u8 result = HandleControlPointCollision(opCode);
		if (result == operation_failed)
		{
			FitnessMachineControlPointResponse(opCode, operation_failed);
			return;
		}
	}
	if (opCode == stop && (length - 1) == 1)
	{
		param.Stop_or_pause_param=pBuf[1];
	}
	if ((length - 1) == 2)
	{ // 有参数
		if (opCode == set_target_speed)
		{
			hw_u16 speedTarget = 0xFF00 & (pBuf[2] << 8);
			speedTarget = speedTarget + pBuf[1];
			param.targetSpeed = speedTarget;
		}
		else if (opCode == set_target_inclination)
		{
			hw_s16 inclinationTarget = 0x7F00 & (pBuf[2] << 8);
			inclinationTarget = inclinationTarget + pBuf[1];
			if ((0xF0 & (pBuf[2] << 8)) == 0xF0)
			{
				inclinationTarget = 0 - inclinationTarget;
			}
			param.targetInclination = inclinationTarget;
		}
	}
	SendAppMachineControlPointToUart(opCode, &param);
	FitnessMachineControlPointResponse(opCode, param.response_state); // 回复APP
}

hw_u8 HandleControlPointCollision(hw_u8 opCode)
{
	hw_u8 currentStatus = GetFitnessMachineStatus();
	switch (g_trainingStatus)
	{
	case idle:
		if (opCode == start)
		{
			return success;
		}
		break;
	case quick_start:
		if (opCode == start)
		{
			return success;
		}
		if (currentStatus == pause_by_user && opCode == pause)
		{
			return operation_failed; // 响应失败
		}
		return success;
//		break;
	case pre_workout:
		return operation_failed;
//		break;
	case post_workout:
		return operation_failed;
//		break;
	default:
		return operation_failed;
//		break;
	}
	return operation_failed;
}
/**
 * 当处理完Fitness Machine Control Point控制指令后
 * 都需要发送一个response给app侧。
 *
 */
void FitnessMachineControlPointResponse(hw_u8 opCode, hw_u8 resultCode)
{
	if (opCode == pause)
	{
		opCode = stop; // 还是按照协议进行封装
	}
	hw_u8 controlPointResponse[3];
	controlPointResponse[0] = 0x80;
	controlPointResponse[1] = opCode;
	controlPointResponse[2] = resultCode;
	SendUartDataToApp(controlPointResponse, 0x03, ORDER_CONTROL_POINT);
}

/**
 * 当opCode为target_speed_changed 和target_incline_changed时parameter有值
 * parameter按小字节序进行传输
 *
 */
void FitnessMachineStatusnotify(hw_u8 opCode, hw_u8 *parameter)
{
	if (opCode == control_permission_lost)
	{
		ResetControlPermission(); // 重置控制权限
	}
	hw_u8 length;
	hw_u8 status[3];
	if ((opCode == target_speed_changed || opCode == target_incline_changed) && length > 1)
	{
		status[0] = opCode;
		status[1] = parameter[0];
		status[2] = parameter[1];
		length = 3;
	}
	else
	{
		g_FitnessMachineStatus = opCode;
		if (opCode == pause_by_user)
		{
			status[0] = stop_by_user;
			status[1] = 0x02;
			length = 2;
		}
		else if (opCode == stop_by_user)
		{
			status[0] = opCode;
			status[1] = 0x01;
			length = 2;
		}
		else
		{
			status[0] = opCode;
			length = 1;
		}
	}
	SendUartDataToApp(status, length, ORDER_STATUS);
}
/**
 * 获取跑步机当前状态,函数名不可更改
 * 状态见fitness_machine_status_operation_code定义
 * 当用户通过面板设置了跑步机状态后，MCU将状态同步给蓝牙模块。
 */
hw_u8 GetFitnessMachineStatus()
{
	// 需要支持以下几种状态
	//			pause_by_user = 0x00,			// 用户暂停
	//			status_reset = 0x01,			// 参数：无      状态重置
	//			stop_by_user = 0x02,			// 用户停止 参数：无
	//			start_by_user = 0x04,			// 参数：无   由用户启动或恢复健身器
	return g_FitnessMachineStatus;
}
/**
 * 解析扩展数据
 *
 */
void fitnessExtensionDataWrite(hw_u8 *pBuf, hw_u8 length)
{
	if (pBuf == NULL || length <= 2)
	{
		return;
	}
	huawei_fitness_extension_data_t extensionData;
	hw_u16 flags = pBuf[0] + (pBuf[1] << 8);
	extensionData.flags = flags;
	int dataIndex = 2;
	hw_u8 flagBit = 0x01;
	for (int i = 0; i < 8; i++)
	{
		flagBit = 0x01 << i;
		if ((flags & flagBit) == flagBit)
		{ // 遍历flag每一位
			switch (i)
			{
			case 0: // unLockCode,6个字节
				if (length > 6)
				{
					// addUnlockCode(&extensionData, pBuf, length);
					dataIndex += 6;
				}
				break;
			case 1: // 心率数据
				if (length >= (dataIndex + 1))
				{
					extensionData.heartRate = pBuf[dataIndex];
					dataIndex += 1;
				}
				break;
			case 2: // 总能量
				if (length >= (dataIndex + 2))
				{
					hw_u16 data_value = 0x0000;
					data_value = data_value | pBuf[dataIndex + 1];
					data_value = data_value << 8;
					data_value = data_value | pBuf[dataIndex];
					extensionData.totalEnergy = data_value;
					dataIndex += 2;
				}
				break;
			case 3: // 动态能量
				if (length >= (dataIndex + 2))
				{
//					hw_u16 data_value = 0x0000;
//					data_value = data_value | pBuf[dataIndex + 1];
//					data_value = data_value << 8;
//					data_value = data_value | pBuf[dataIndex];
//					extensionData.dynamicEnerty = data_value;
					dataIndex += 2;
				}
				break;
			case 4: // 总步数
				if (length >= (dataIndex + 2))
				{
					hw_u16 data_value = 0x0000;
					data_value = data_value | pBuf[dataIndex + 1];
					data_value = data_value << 8;
					data_value = data_value | pBuf[dataIndex];
					extensionData.steps = data_value;
					dataIndex += 2;
				}

				break;
			case 5: // 运行时间
				if (length >= (dataIndex + 2))
				{
					hw_u16 data_value = 0x0000;
					data_value = data_value | pBuf[dataIndex + 1];
					data_value = data_value << 8;
					data_value = data_value | pBuf[dataIndex];
					extensionData.remaining_time = data_value;
					dataIndex += 2;
				}
				break;
			case 6: // RGB 颜色码
				if (length >= (dataIndex + 3))
				{
//					extensionData.RGBColorTable[0] = pBuf[dataIndex + 2]; // G
//					extensionData.RGBColorTable[1] = pBuf[dataIndex];	  // B
//					extensionData.RGBColorTable[2] = pBuf[dataIndex + 1]; // R
					dataIndex += 3;
				}
				break;
			case 7: // 运动里程
				if (length >= (dataIndex + 3))
				{
					unsigned long data_value = 0x0000;
					data_value = data_value | pBuf[dataIndex + 2];
					data_value = data_value << 8;
					data_value = data_value | pBuf[dataIndex+1];
					data_value = data_value << 8;
					data_value = data_value | pBuf[dataIndex];
					extensionData.totalDistance = data_value;
					dataIndex += 3;
				}
				break;
			default:
				break;
			}
		}
	}
	SendAppExtensionDataToUart(&extensionData);
}

/**
 * 蓝牙断开会调用该函数
 * 重置控制命令授权状态
 */
void ResetControlPermission(void)
{
	g_controlPointStatus = verify_failed;
}

/**
 * 蓝牙授权会调用该函数
 *
 */
void SetControlPermissionToSuccess()
{
	g_controlPointStatus = verify_success;
}

/**
 * 蓝牙断开会调用该函数
 * 重置解锁码校验状态
 *
 */
void ResetWhenBluetoothDisconnect()
{
	ResetControlPermission();
}
